package com.onpositive.data.serializer.readers;

import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.BitSet;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedHashSet;

import com.onpositive.data.FilterTester;
import com.onpositive.data.serializer.writers.AbstractWriter;
import com.onpositive.data.serializer.writers.DateWriter;
import com.onpositive.data.units.DateWithAccuracy;


public class DateReader extends CollectionReader<Date> {
	
//	private static final int INT_SIZE = 4 ;
	private final static Date defaultDate = new Date(0) ;
	private static final int defaultIntValue = Integer.MIN_VALUE ;

	private GregorianCalendar cl = new GregorianCalendar();
	private int[] primitiveValuesArrays;

	public DateReader(){
		super( Date.class );
	}
	
	@Override
	protected void initValuesAray(byte[] byteData) {
		
		primitiveValuesArrays = new int[size];
		
		ByteBuffer bBuf = ByteBuffer.wrap( byteData ) ;
		
		boolean continueIteration = true ;
		int start = 0 ;
		int end = emptyCells.nextSetBit(0) ;
		for(  ; continueIteration ;  )
		{			
			for( int i = start ; i < end ; i++ )
				primitiveValuesArrays[i] = bBuf.getInt() ;			

			if( end < size )
				primitiveValuesArrays[end] = defaultIntValue ;

			start = end+1 ;
			end = emptyCells.nextSetBit( start ) ;
			end = end >= 0 ? end : size ;
			continueIteration = start <= size ;			
		}		
	}
	
	@Override
	protected Date doGet( int i )
	{		
		return createDate( primitiveValuesArrays[i]);
	}

	
	@Override
	protected Date defaultObject() {
		return defaultDate ;
	}

	@Override
	protected Date readObject(ByteBuffer bBuf) {
		
		return createDate( bBuf.getInt() );
	}
	
	private Date createDate(int val) {

		int day = val & ( (1<<9)-1 ) ;
		val >>= 9 ;

		cl.set( GregorianCalendar.YEAR, val ) ;
		cl.set( GregorianCalendar.DAY_OF_YEAR, day ) ;
		
		
		Date date = cl.getTime() ;

		return date ;
	}

	@Override
	public void filterOut(LinkedHashSet<Object> obj, String text) {
		
	}


	
	@Override
	public boolean accept(int op, int a, Object constraint) {
		if (!isInitialized())
			init();
		boolean b = emptyCells.get(a);
		if (constraint == null) {
			switch (op) {
			case FilterTester.LE:
			case FilterTester.GE:
			case FilterTester.EQ:
				return b;

			case FilterTester.LT:
			case FilterTester.GT:
			case FilterTester.NEQ:
				return !b;

			default:
				break;
			}
			return false;
		}
		if (b) {
			switch (op) {
			case FilterTester.LE:
			case FilterTester.NEQ:
			case FilterTester.LT:
				return true;

			default:
				break;
			}
			return false;
		}
		if (constraint instanceof DateWithAccuracy){
			DateWithAccuracy m=(DateWithAccuracy) constraint;
			constraint=m.getDate();
		}
		long i = createDate(primitiveValuesArrays[a]).getTime();
		//FIXME
		Date m = (Date) constraint;

		long ww = m.getTime();
		
		switch (op) {
		case FilterTester.EQ:
			return ww == i;
		case FilterTester.NEQ:
			return ww != i;
		case FilterTester.GE:
			return ww >= i;
		case FilterTester.GT:
			return ww > i;
		case FilterTester.LT:
			return ww < i;
		case FilterTester.LE:
			return ww <= i;
		case FilterTester.CONTAINS:
			return ww == i;
		default:
			throw new UnsupportedOperationException();
		}
	}


	@Override
	public Object aggregate(int op, BitSet ss) {
		if (!isInitialized()) {
			init();
		}
		ComparingAggregator comparingAggregator = new ComparingAggregator();
		comparingAggregator.mode=(op==AGR_MIN)?ComparingAggregator.MIN_MODE:ComparingAggregator.MAX_MODE;
		Comparable[]vls=new Comparable[primitiveValuesArrays.length];
		for (int a=0;a<vls.length;a++){
			vls[a]=getObject(a);
		}
		return comparingAggregator.getAggregatedValue(vls,ss);
	}

	@Override
	public void setValue(int num, Object value) {
		throw new UnsupportedOperationException();
	}

	@Override
	public AbstractWriter<Date> getWriter() {
		return new DateWriter();
	}

	@Override
	public void initEmpty(int dataSize) {
		primitiveValuesArrays=new int[dataSize];
		setInitialized();
	}

	@Override
	public void expand(int newSize) {
		if (!isInitialized()){
			init();
		}
		int[] m=new int[newSize];
		System.arraycopy(primitiveValuesArrays, 0, m, 0, primitiveValuesArrays.length);
		for (int a=primitiveValuesArrays.length;a<m.length;a++){
			m[a]=defaultIntValue;
		}
		primitiveValuesArrays=m;
	}
}
